/*****************************************************************************/
/*                        >>> func_PPD.c-- <<<                               */
/*	Trabajo Practico 2do. cuatrimestre 2011                                  */
/*	TP:"FUSELAJE"                                                            */
/*	GRUPO: Reduce Fat Fast                                                   */
/*	INTEGRANTES: Emanuel Genovese                                            */
/*               Federico Gabriel Garcia                                     */
/*               Federico Pioli                                              */
/*               Esther Insfrain                                             */
/*               Luciano Bagattin                                            */
/*	Fecha UM:                                                                */
/*****************************************************************************/
/*****************************************************************************/
/*		        	HEADERS					                                 */
/*****************************************************************************/
#include "../headers/func_PPD.h"
#include "constants_commons.h"

/*****************************************************************************/
/*		        	DEFINE					                                 */
/*****************************************************************************/
#include <stdio.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/un.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include "../headers/constantes.h"
#include "../headers/func_Disco.h"
#include "func_socket.h"
#include "func_strings.h"
#include "structs_commons.h"
#include "func_ipc.h"

/******************************************************************************/
/* Nombre de Funcion: fProcesarConsola                                        */
/* Parametros: master: bolsa de sockets
 *             st: estructura del archivo de configura                        */
/* Descripcion: Funcion que hace el procesamiento de la consola como hijo     */
/******************************************************************************/

int fProcesarConsola(datosConfig st, t_log *log) {
	/* declaracion de variables locales*/

	int i, iListenConsola;

	/*Fin de la declaracion de variables locales*/

	if ((strcmp(st.sConsola, "S")) == 0) {

		iListenConsola = fPrepararSocket_UN(log, SNOMBREPROCESO);
		if (fEscuchaSocketUN(iListenConsola, SNOMBREPROCESO, log,
				st.sPathConsola)) {
			log_error(log, SNOMBREPROCESO, "Message error: %s",
					"Error en la escucha del socket");
			return -1;
		} //fin del fEscuchaSocketUN

		/*Creamos el hijo de la consola*/
//		  if ((i=fork())==0){ /* Estoy en el hijo */
//		  	  if(execl(RUTA_CONSOLA, "PDD_CONSOLA", st.sPathConsola,NULL)<0){
//		  		log_error(log, SNOMBREPROCESO, "Message error: %s", "Error en la creacion del hijo ");
//		  	   return -1;
//		  	  }
//
//		  }else if(i<0){
//			  //Error en la creacion del hijo
//			return 1;
//		  }
	} //fin del if

	return iListenConsola;
}

/******************************************************************************/
/* Nombre de Funcion: fProcesarServer                                         */
/* Parametros: puntero: cmrMatriz de lineas de arch config                    */
/*																			  */
/*	                                                                          */
/* Descripcion: Funcion que hace el procesamiento del ppd como server         */
/******************************************************************************/

int fProcesarServer(datosConfig st, t_log *log) {
	/*declaracion de variables locales*/

	int iListen, iSockListen, iSockPFS, iListenConsola, i, iAcceptConsola;
	int iFdMax = -1;

	unsigned int t;
	struct sockaddr_in Str_sockaddr_in_paraAcept;
	char sPuertoLocal[6] = "\0";
	struct sockaddr_un sockaddr_shell;
	fd_set master;
	unsigned int iAddress_size = sizeof(struct sockaddr_in);

	stNIPC stRIPC;
	stNIPC stSIPC;

	/*fin de la declaracion de variables locales*/

	FD_ZERO(&master);
	iListenConsola = fProcesarConsola(st, log);
	if (iListenConsola == -1) {
		log_error(log, SNOMBREPROCESO, "Message error: %s",
				"Error en el procesarConsola ");
		return -1;
	} //fin del if

	FD_SET(iListenConsola, &master);
	pIntacad(st.iPuertoLocal, sPuertoLocal);

	iSockListen = fPrepararSocket(sPuertoLocal, st.sIpLocal,
			"Socket para conexion de file System", 0, LOG, SNOMBREPROCESO, log);

	if (iSockListen == -1) {
		printf("Se produjo un error en la creacion del socket para esperar conexiones");
		log_error(log, SNOMBREPROCESO, "Message error: %s",
				"Error en la creacion del socket para esperar conexiones ");

		return -1;
	} //fin del if
	log_info(log, SNOMBREPROCESO, "Message info: %s",
			"Exito en la creacion del socket para esperar conexiones ");

	//Verificamos que este escuchando conexiones entrantes
	iListen = fEscuchar(iSockListen, 100, LOG, SNOMBREPROCESO, log);

	if (iListen == 0) {
		printf(
				"Se produjo un error en la escucha de sockets para las conexiones");
		log_error(log, SNOMBREPROCESO, "Message error: %s",
				"Error en la escucha de sockets para las conexiones ");

		return -1;
	} //fin del if
	log_info(log, SNOMBREPROCESO, "Message info: %s",
			"Exito en la escucha de sockets para las conexiones ");

	if ((iAcceptConsola = accept(iListenConsola,
			(struct sockaddr *) &sockaddr_shell, &t)) == -1) {

		log_error(log, SNOMBREPROCESO, "Message error: %s",
				"Error al aceptar conexion entrante de la consola ");
		return -1;
	}
	log_info(log, SNOMBREPROCESO, "Message info: %s",
			"Exito al aceptar conexion entrante de la consola");

	iFdMax = iAcceptConsola;
	FD_SET(iAcceptConsola, &master);

	while (1) {

		if (select(iFdMax + 1, &master, NULL, NULL, NULL) == -1) {
			log_error(log, SNOMBREPROCESO, "Message error: %s",
					"Error en el select");
			return -1;
		} else {

			for (i = 0; i <= iFdMax; i++) {

				/*Nos llega algo de la consola*/
				if (FD_ISSET(i, &master)) {

					if (i == iAcceptConsola) {

						//Atender Pedidos de Consola
						if (fProcesarPedidos(iAcceptConsola, log) == -1) {
							return -1;
						};

					} //fin del if (eventos[i].events & EPOLLIN)

					if (i == iListen) {
						//acepto conexiones pueden ser o peticiones de clientes o conexiones de clientes
						if ((iSockPFS = (int) accept(iSockListen,
								(struct sockaddr *) &Str_sockaddr_in_paraAcept,
								&iAddress_size)) == -1) {
							log_error(log, SNOMBREPROCESO, "Message error: %s",
									"Error en el accept de Pedidos");
							return 1;
						} //fin del accept
						FD_SET(iSockPFS, &master);
						if (iFdMax < iSockPFS) {
							iFdMax = iSockPFS;
						} //fin del if

					}

					if ((i != iAcceptConsola) && (i != iListen)) {

						if (fRecibirIPCXsocket(i, &stRIPC, log)) {
							return -1;
							break;
						} //fin del ifRecibirIPCXsocket

						if ((stRIPC.iType == 0)
								&& (stRIPC.iPayloadDescriptor == CONNECT_PFS)) {
							stSIPC.iPayloadDescriptor = CONNECT_OK;
							stSIPC.iType = 0;
						} else {
							stSIPC.iPayloadDescriptor = CONNECT_FAIL;
							stSIPC.iType = 0;
						} //fin del if
						  //Envio respuesta del handshake
						if (fMandarIPCXsocket(i, stSIPC, log)) {
							return -1;
							break;
						} //fin del if
						if (stSIPC.iPayloadDescriptor != CONNECT_OK) {
							FD_CLR(i, &master);
							close(i);

						} else {
							fProcesarPedidos(i, log);
						} //fin del if (stSIPC.iPayloadDescriptor == CONNECT_FAIL

					}
				}

			} //fin del for(i=0;i < res;i++)
		}
	} //while

	return 0;
} //fin del fProcesarServer

/******************************************************************************/
/* Nombre de Funcion: fProcesarCliente                                        */
/* Parametros: puntero: cmrMatriz de lineas de arch config                    */
/*																			  */
/*	                                                                          */
/* Descripcion: Funcion que realiza el procesamiento del ppd como cliente     */
/******************************************************************************/
int fProcesarCliente(datosConfig st, t_log *log) {
	/*declaracion de variables locales*/
	int iListenConsola, iSockListen, iListen, iAcceptConsola, iFdMax;
	fd_set master;
	char sPuertoLocal[16];
	struct sockaddr_un sockaddr_shell;
	unsigned int t;
	/*fin declaracion de variables locales*/

	FD_ZERO(&master);
	iListenConsola = fProcesarConsola(st, log);

	FD_SET(iListenConsola, &master);

	iSockListen = fPrepararSocket(sPuertoLocal, st.sIpLocal,
			"Socket para conexion de file System", 0, LOG, SNOMBREPROCESO, log);

	if (iSockListen == -1) {
		printf(
				"Se produjo un error en la creacion del socket para esperar conexiones");
		log_error(log, SNOMBREPROCESO, "Message error: %s",
				"Error en la creacion del socket para esperar conexiones ");
		log_destroy(log);
		return 1;
	} //fin del if
	log_info(log, SNOMBREPROCESO, "Message info: %s",
			"Exito en la creacion del socket para esperar conexiones ");

	//Verificamos que este escuchando conexiones entrantes
	iListen = fEscuchar(iSockListen, 100, LOG, SNOMBREPROCESO, log);

	if (iListen == 0) {
		printf(
				"Se produjo un error en la escucha de sockets para las conexiones");
		log_info(log, SNOMBREPROCESO, "Message error: %s",
				"Error  en la escucha de sockets para las conexiones ");
		log_destroy(log);
		return 1;
	} //fin del if
	t = sizeof(sockaddr_shell);

	if ((iAcceptConsola = accept(iListenConsola,
			(struct sockaddr *) &sockaddr_shell, &t)) == -1) {

		log_error(log, SNOMBREPROCESO, "Message error: %s",
				"Error al aceptar conexion entrante de la consola ");
	} else {

		log_info(log, SNOMBREPROCESO, "Message info: %s",
				"Exito al aceptar conexion entrante de la consola");

	} //fin del if (iAcceptConsola

	iFdMax = iAcceptConsola;

	return 0;
} //fin del fProcesarCliente

